package com.start.ws.connect;

import com.start.common.exceptions.StartBusException;
import com.start.common.tools.SpringContextTools;
import com.start.ws.listener.IStartSocketSendMsgListener;
import com.start.ws.listener.IStartUserLifeCycleListener;
import jakarta.websocket.Session;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 连接管理
 */
public class StartConnectManager implements StartConnectLifeCycle, IStartUserLifeCycleListener {
    private static final StartConnectManager manager = new StartConnectManager();
    private static final Map<String, StartUserConnect> concurrentHashMap = new ConcurrentHashMap<>();
    private static Map<String, IStartSocketSendMsgListener> listenerMap;
    private static Map<String, IStartUserLifeCycleListener> userLifeCycleListenerMap;

    private StartConnectManager() {
        if (manager != null) throw new StartBusException("管理对象部门被多次创建");
        try {
            listenerMap = SpringContextTools.getBeans(IStartSocketSendMsgListener.class);
            userLifeCycleListenerMap = SpringContextTools.getBeans(IStartUserLifeCycleListener.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取当前连接管理器
     *
     * @return
     */
    public static StartConnectManager getInstance() {
        return manager;
    }

    /**
     * 用户连接时触发
     *
     * @param startUserType
     * @param clientType    连接人客户端类型
     * @param userId        连接人用户id
     * @param session       当前连接
     */
    @Override
    public void onConnect(String startUserType, String clientType, String userId, Session session) {
        String userKey = getUserKey(startUserType, userId);
        StartUserConnect userConnect = concurrentHashMap.getOrDefault(userKey, null);
        if (userConnect == null) {
            userConnect = new StartUserConnect(startUserType, userId);
            concurrentHashMap.put(userKey, userConnect);
        }
        userConnect.addSession(clientType, session);
        onConnect(userConnect, session);
    }

    public static String getUserKey(String startUserType, String userId) {
        return startUserType + ":" + userId;
    }

    @Override
    public void onClose(String startUserType, String clientType, String userId, Session session) {
        StartUserConnect userConnect = concurrentHashMap.getOrDefault(getUserKey(startUserType, userId), null);
        if (userConnect == null) {
            return;
        }
        userConnect.close(clientType, session.getId());
    }

    /**
     * 发送消息
     *
     * @param userKey          用户id
     * @param msg              消息内容
     * @param targetClientType 目标客户端类型
     * @return
     */
    public boolean sendMsg(String userKey, String msg, String targetClientType) {
        return sendMsg(msg, userKey, targetClientType, true);
    }

    /**
     * 发送消息
     *
     * @param startUserType    接收人用户体系
     * @param userId           接收人用户id
     * @param msg              消息内容
     * @param targetClientType 客户端类型
     * @return
     */
    public boolean sendMsg(String startUserType, String userId, String msg, String targetClientType) {
        String userKey = getUserKey(startUserType, userId);
        return sendMsg(userKey, msg, targetClientType, true);
    }

    /**
     * 发送消息
     *
     * @param userKey          用户id
     * @param msg              消息内容
     * @param targetClientType 目标客户端类型
     * @param enableBroadcast  是否启用广播
     * @return
     */
    public boolean sendMsg(String userKey, String msg, String targetClientType, boolean enableBroadcast) {
        if (StringUtils.isEmpty(msg)) {
            return false;
        }
        if (StringUtils.isEmpty(userKey)) {
            return false;
        }
        if (!concurrentHashMap.containsKey(userKey)) {
            return handlerBorderCast(msg, userKey, targetClientType, enableBroadcast);
        }
        StartUserConnect startUserConnect = concurrentHashMap.get(userKey);
        boolean sendMsg = startUserConnect.sendMsg(targetClientType, msg);
        if (!sendMsg) {
            return handlerBorderCast(msg, userKey, targetClientType, enableBroadcast);
        }
        return true;
    }

    /**
     * 发送消息
     *
     * @param startUserType    接收人用户体系
     * @param userId           接收人用户id
     * @param msg
     * @param targetClientType 客户端类型
     * @param enableBroadcast  是否开启广播
     * @return
     */
    public boolean sendMsg(String startUserType, String userId, String msg, String targetClientType, boolean enableBroadcast) {
        String userKey = getUserKey(startUserType, userId);
        return sendMsg(userKey, msg, targetClientType, enableBroadcast);
    }

    /**
     * 判断用户是否在线
     *
     * @param userKey 用户id
     * @return
     */
    public boolean hasUser(String startUserType, String userKey) {
        return hasUser(startUserType, userKey, null);
    }

    /**
     * 判断用户是否在线
     *
     * @param userId     用户id
     * @param clientType 用户客户端id
     * @return
     */
    public boolean hasUser(String startUserType, String clientType, String userId) {
        String userKey = getUserKey(startUserType, userId);
        if (StringUtils.isEmpty(userKey)) return false;
        if (!concurrentHashMap.containsKey(userKey)) {
            return false;
        }
        StartUserConnect startUserConnect = concurrentHashMap.get(userKey);
        if (startUserConnect == null) {
            concurrentHashMap.remove(userId);
            return false;
        }
        if (StringUtils.isEmpty(clientType)) {
            return true;
        }
        return startUserConnect.hasClientType(clientType);
    }

    /**
     * 处理广播类型
     *
     * @param msg              消息
     * @param userKey          用户
     * @param targetClientType 接收人客户端类型
     * @param enableBroadcast  是否广播
     * @return
     */
    private boolean handlerBorderCast(String msg, String userKey, String targetClientType, boolean enableBroadcast) {
        if (!enableBroadcast) {
            return false;
        }
        if (listenerMap == null || listenerMap.isEmpty()) {
            return false;
        }
        Collection<IStartSocketSendMsgListener> values = listenerMap.values();
        for (IStartSocketSendMsgListener value : values) {
            value.onSendMsg(userKey, msg, targetClientType);
        }
        return true;
    }

    @Override
    public void onConnect(StartUserConnect userConnect, Session session) {
        if (userLifeCycleListenerMap == null || userLifeCycleListenerMap.isEmpty()) return;
        Collection<IStartUserLifeCycleListener> values = userLifeCycleListenerMap.values();
        for (IStartUserLifeCycleListener value : values) {
            try {
                value.onConnect(userConnect, session);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onClose(StartUserConnect userConnect, String clientType, Session session) {
        if (userLifeCycleListenerMap == null || userLifeCycleListenerMap.isEmpty()) return;
        Collection<IStartUserLifeCycleListener> values = userLifeCycleListenerMap.values();
        for (IStartUserLifeCycleListener value : values) {
            try {
                value.onClose(userConnect, clientType, session);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
